package com.tanhua.server.interceptor;

import com.tanhua.common.pojo.User;
import com.tanhua.common.utils.NoAuthorization;
import com.tanhua.common.utils.UserThreadLocal;
import com.tanhua.server.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class UserTokenInterceptor implements HandlerInterceptor {

    @Autowired
    private UserService userService;

    /**
     * 拦截请求 校验token并将  返回的user调用线程存储工具类 将user存入对应的线程中
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 校验handler是否是HandlerMethod
        if (!(handler instanceof HandlerMethod)){
            // 如果不是请求控制器的方法 那么直接放行
            return true;
        }

        // 判断是否包含@NoAuthorization注解，如果包含，直接放行
        if (((HandlerMethod) handler).hasMethodAnnotation(NoAuthorization.class)){
            return true;
        }

        // 从请求头中获取token
        String token = request.getHeader("Authorization");
        if (StringUtils.isNotEmpty(token)){
            // 如果token不为空 则进行校验token
            User user = userService.queryUserByToken(token);

            if (user != null){
                // 如果返回的对象不为空  则将user对象存入对应的线程储存对象中
                UserThreadLocal.set(user);
                return true;
            }
        }

        // 如果校验token失败 则响应401状态码,表示用户需要进行权限验证
        response.setStatus(401);
        return false;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response
            , Object handler, Exception ex) throws Exception {
        //响应结束后，从ThreadLocal中移除User对象，如果不进行删除那么这条线程被放回线程池之后，这个对象还是会存在，
        // 如果其他的用户访问恰好调用该线程，那么使用的用户信息就会出错
        UserThreadLocal.remove();
    }
}
